package cn.duli.xianer.controller;

import cn.duli.xianer.config.AlipayConfig;
import cn.duli.xianer.pojo.MyResult;
import cn.duli.xianer.pojo.Orders;
import cn.duli.xianer.pojo.Transfer;
import cn.duli.xianer.pojo.UserAuth;
import cn.duli.xianer.service.OrderRefundService;
import cn.duli.xianer.service.OrdersService;
import cn.duli.xianer.service.TransferService;
import cn.duli.xianer.service.UserAuthService;
import cn.duli.xianer.utils.StrUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.*;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayAssetCardTransferRequest;
import com.alipay.api.request.AlipayFundTransUniTransferRequest;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

@Controller
@RequestMapping("/alipay")
public class AlipayController {


    String app_id = AlipayConfig.app_id;
    String private_key = AlipayConfig.private_key;
    String notify_url = AlipayConfig.notify_url;
    String return_url = AlipayConfig.return_url;
    String url = AlipayConfig.url;
    String charset = AlipayConfig.charset;
    String format = AlipayConfig.format;
    String public_key = AlipayConfig.public_key;
    String signtype = AlipayConfig.signtype;

    private String path = Thread.currentThread().getContextClassLoader().getResource("").getPath();
    private String certPath = path + "/static/appCertPublicKey_2016092700606084.crt";
    private String publicCertPath = path + "/static/alipayCertPublicKey_RSA2.crt";
    private String rootCertPath = path + "/static/alipayRootCert.crt";

    @Autowired
    private OrdersService ordersService;

    @Autowired
    private OrderRefundService orderRefundService;

    @Autowired
    private UserAuthService userAuthService;

    @Autowired
    private TransferService transferService;

    @RequestMapping("/pay")
    public void pay(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 获取订单号、支付金额
        String orderNo = (String) request.getParameter("orderNo");
        String price = request.getParameter("price");

        System.out.println(orderNo+price);

        String subject = "闲贰商品交易订单"; // 订单名称
        String body = "xianer";

        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
        certAlipayRequest.setServerUrl(url);
        certAlipayRequest.setAppId(app_id);
        certAlipayRequest.setPrivateKey(private_key);
        certAlipayRequest.setFormat(format);
        certAlipayRequest.setCharset(charset);
        certAlipayRequest.setSignType(signtype);
        certAlipayRequest.setCertPath(certPath);
        certAlipayRequest.setAlipayPublicCertPath(publicCertPath);
        certAlipayRequest.setRootCertPath(rootCertPath);
        DefaultAlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest);
        //todo 构建request内容
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
//        alipayRequest.setReturnUrl("http://localhost:8081/" + return_url);
        alipayRequest.setReturnUrl("http://localhost:8081/#/returnUrl");
        alipayRequest.setNotifyUrl("http://localhost:8081/#/" + notify_url);
        AlipayTradePayModel model = new AlipayTradePayModel();
        model.setOutTradeNo(orderNo);// 设置订单号
        model.setProductCode("FAST_INSTANT_TRADE_PAY");// 设置销售产品码
        model.setTotalAmount(price);// 设置价格
        model.setSubject(subject);// 设置订单名称
        model.setBody(body);// 设置商品描述
        model.setTimeoutExpress("30m");// 设置订单关闭时间
        alipayRequest.setBizModel(model);
        String form = "";
        try {
            form = alipayClient.pageExecute(alipayRequest).getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        response.setContentType("text/html;charset=" + charset);
        response.getWriter().write(form);//直接将完整的表单html输出到页面
        response.getWriter().flush();
        response.getWriter().close();
    }

    @RequestMapping("/returnUrl")
    @ResponseBody
    public MyResult returnUrl(HttpServletRequest request) throws Exception {
        // 获取支付宝GET过来反馈信息（官方固定代码）
        Map<String, String> params = new HashMap<>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
            System.out.println(name + ":" + valueStr);
        }
        boolean signVerified = AlipaySignature.rsaCheckV1(params, public_key, charset, signtype); // 调用SDK验证签名
        // 返回界面
        if (signVerified) {
            String orderNo = params.get("out_trade_no");
            String alipayNo = params.get("trade_no");
            //添加支付时间
            String time= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(System.currentTimeMillis());
            List<Orders> ordersList = ordersService.findByParentNo(orderNo);
            for (int i=0;i<ordersList.size();i++) {
                // 更新订单信息Long.parseLong(orderNo)
                ordersService.updateOrderStatusByoNo(orderNo, time, alipayNo);
            }
            System.out.println("前往支付成功页面");
            System.out.println(orderNo);
            System.out.println(alipayNo);
            return new MyResult(200, "支付成功",null,null,alipayNo,null);
        } else {
            String orderNo = params.get("out_trade_no");
            String alipayNo = params.get("trade_no");
            //添加支付时间
            String time= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(System.currentTimeMillis());
            List<Orders> ordersList = ordersService.findByParentNo(orderNo);
            for (int i=0;i<ordersList.size();i++) {
                // 更新订单信息
                ordersService.updateOrderStatusByoNo(orderNo, time, alipayNo);
            }
            System.out.println("前往支付失败页面");
            System.out.println(orderNo);
            System.out.println(alipayNo);
            return new MyResult(400, "支付失败",null,null,alipayNo,null);
        }
    }

    /**
     * 支付宝服务器异步通知（是在真实环境中字符成功后收到的消息通知，在支付宝后台完成的异步操作）
     *
     * @param request
     * @throws Exception
     */
    @RequestMapping("/notifyUrl")
    public void notifyUrl(HttpServletRequest request) throws Exception {
        System.out.printf("支付宝服务器异步通知");
        // 获取支付宝GET过来反馈信息
        Map<String, String> params = new HashMap<>();
        Map<String, String[]> requestParams = request.getParameterMap();

        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
            System.out.println(name + ":" + valueStr);
        }

        boolean signVerified = AlipaySignature.rsaCheckV1(params, public_key, charset, signtype); // 调用SDK验证签名

        if (signVerified) { // 验证成功 更新订单信息
            System.out.println("异步通知成功");
            // 商户订单号
            String out_trade_no = request.getParameter("out_trade_no");
            // 支付宝交易流水号
            String alipayNo = params.get("trade_no");
            // 交易状态
            String trade_status = request.getParameter("trade_status");
            //添加支付时间
            String time= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(System.currentTimeMillis());
            List<Orders> ordersList = ordersService.findByParentNo(out_trade_no);
            for (int i=0;i<ordersList.size();i++) {
                // 更新订单信息
                ordersService.updateOrderStatusByoNo(out_trade_no, time, alipayNo);
            }
        } else {
            System.out.println("异步通知失败");
            // 商户订单号
            String out_trade_no = request.getParameter("out_trade_no");
            // 支付宝交易流水号
            String alipayNo = params.get("trade_no");
            // 交易状态
            String trade_status = request.getParameter("trade_status");
            //添加支付时间
            String time= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(System.currentTimeMillis());
            List<Orders> ordersList = ordersService.findByParentNo(out_trade_no);
            for (int i=0;i<ordersList.size();i++) {
                // 更新订单信息
                ordersService.updateOrderStatusByoNo(out_trade_no, time, alipayNo);
            }
        }
    }


    /**
     * 退款
     * @return
     * @throws AlipayApiException
     */
    @RequestMapping("/refund")
    @ResponseBody
    public MyResult refund(Integer orId,String parentNo,String alipayNo,String price,String reason) throws AlipayApiException {
        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
        certAlipayRequest.setServerUrl(url);
        certAlipayRequest.setAppId(app_id);
        certAlipayRequest.setPrivateKey(private_key);
        certAlipayRequest.setFormat(format);
        certAlipayRequest.setCharset(charset);
        certAlipayRequest.setSignType(signtype);
        certAlipayRequest.setCertPath(certPath);
        certAlipayRequest.setAlipayPublicCertPath(publicCertPath);
        certAlipayRequest.setRootCertPath(rootCertPath);
        DefaultAlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest);
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        AlipayTradeRefundModel model = new AlipayTradeRefundModel();
        // 需要修改下面三个参数，可以打开支付宝沙箱的账单查询
        model.setOutTradeNo(parentNo);
        model.setTradeNo(alipayNo);
        model.setRefundAmount(price);
        model.setRefundReason(reason);
        model.setOutRequestNo(StrUtil.getOrderNo());  // 部分退款需加上，随机生成就可
        request.setBizModel(model);
        AlipayTradeRefundResponse response = alipayClient.certificateExecute(request);
        if(response.isSuccess()){
            // 执行退款成功操作
            // 更新退款状态为退款成功
            orderRefundService.updateRefundStatus(1, orId);
            return new MyResult(200, "退款成功",null,null,response.getBody(),null);
        } else {
            // 执行退款失败操作
            return new MyResult(400, "退款失败",null,null,null,null);
        }
    }


    /**
     * 单笔转账到支付宝账户
     * @return
     * @throws ServletException
     * @throws IOException
     * @throws AlipayApiException
     */
    @RequestMapping("/transfer")
    @ResponseBody
    public MyResult transfer(@RequestParam("oId") Integer oId) throws ServletException, IOException, AlipayApiException {
        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
        certAlipayRequest.setServerUrl(url);
        certAlipayRequest.setAppId(app_id);
        certAlipayRequest.setPrivateKey(private_key);
        certAlipayRequest.setFormat(format);
        certAlipayRequest.setCharset(charset);
        certAlipayRequest.setSignType(signtype);
        certAlipayRequest.setCertPath(certPath);
        certAlipayRequest.setAlipayPublicCertPath(publicCertPath);
        certAlipayRequest.setRootCertPath(rootCertPath);
        DefaultAlipayClient alipayClient = new DefaultAlipayClient(certAlipayRequest);
        AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
        // 根据订单id查询订单信息
        Orders order = ordersService.findById(oId);
        // 根据商品发布者的用户id查询此订单商品的卖家信息，得到卖家支付宝号
        UserAuth userAuth = userAuthService.findByUserId(order.getGoods().getgUid());
        AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();
        model.setOutBizNo(order.getoOrderNum());
        BigDecimal bigPrice = order.getoTotalAmount().multiply(new BigDecimal(0.95));
        model.setTransAmount(String.valueOf(bigPrice.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue()));
        model.setProductCode("TRANS_ACCOUNT_NO_PWD");
        model.setBizScene("DIRECT_TRANSFER");
        model.setOrderTitle("普通转账");
        Participant participant = new Participant();
        participant.setIdentity(userAuth.getUaAlipay());
        participant.setIdentityType("ALIPAY_LOGON_ID");
        participant.setName("沙箱环境");
        model.setPayeeInfo(participant);
        model.setRemark("普通转账");
        request.setBizModel(model);
        AlipayFundTransUniTransferResponse response = alipayClient.certificateExecute(request);
        if(response.isSuccess()){
            // 新增转账记录
            Transfer transfer = new Transfer();
            transfer.settAlipay(userAuth.getUaAlipay());
            transfer.settOid(oId);
            transfer.settOno(order.getoOrderNum());
            transfer.settServicePrice(order.getoTotalAmount().multiply(new BigDecimal(0.05)).setScale(2, BigDecimal.ROUND_HALF_UP));
            transfer.settPrice(bigPrice.setScale(2, BigDecimal.ROUND_HALF_UP));
            transfer.settDesc("订单" + oId + "：交易成功转账");
            int tId = transferService.save(transfer);
            return new MyResult(200, "转账成功",null,null,tId,null);
        } else {
            return new MyResult(400, "转账失败",null,null,null,null);
        }
    }
}
